package lexico;

import java.util.ArrayList;
import java.util.List;

public class AnalisadorLexico
{
	private String codigoFonte;
	private List<Simbolo> listaSimbolos;
	private List<ClasseSimbolo> listaClasses;
	private boolean obteveSimbolo;
	private int pLeitura;

	public AnalisadorLexico(String codigo)
	{
		codigoFonte = codigo;
		listaSimbolos = new ArrayList<Simbolo>();
		listaClasses = new ArrayList<ClasseSimbolo>();
		pLeitura = -1;

		initClasses();
	}

	private void initClasses()
	{
		listaClasses.add(new ClasseIdentificador(this));
		listaClasses.add(new ClasseNumero(this));
		listaClasses.add(new ClasseOperador(this));
		listaClasses.add(new ClasseLiteral(this));
		listaClasses.add(new ClasseParentese(this));
		listaClasses.add(new ClasseVirgula(this));
	}

	public void analisar()
	{
		while (!isFinal())
		{
			obterSimbolos();
		}

		System.out.println("Simbolos aceitos ...........");

		for (Simbolo s : listaSimbolos)
		{
			System.out.println(s);
		}

		System.out.println("...........");
	}

	private boolean isFinal()
	{
		return pLeitura >= (codigoFonte.length() - 1);
	}

	public void setFinal()
	{
		pLeitura = codigoFonte.length();
	}

	public void recuarLeitura()
	{
		pLeitura--;
	}

	public void addSimbolo(Simbolo simbolo)
	{
		listaSimbolos.add(simbolo);
		obteveSimbolo = true;
	}

	public void naoObteveSimbolo()
	{
		obteveSimbolo = false;
	}

	private void obterSimbolos()
	{
		obteveSimbolo = false;
		String ultimoSimbolo;

		while (!obteveSimbolo)
		{
			try
			{
				ultimoSimbolo = "" + readCharValido();
			} catch (Exception e)
			{
				break;
			}

			for (ClasseSimbolo classe : listaClasses)
			{
				if (classe.test(ultimoSimbolo))
				{
					classe.ler(ultimoSimbolo);
					if (obteveSimbolo)
					{
						break;
					}
				}
			}

			if (!obteveSimbolo)
			{
				System.out.println("Erro:" + ultimoSimbolo);
				break;
			}
		}
	}

	public char readChar() throws Exception
	{
		if (isFinal())
		{
			setFinal();
			throw new Exception();
		}

		pLeitura++;
		return codigoFonte.charAt(pLeitura);
	}

	private char readCharValido() throws Exception
	{
		char c = readChar();

		while (c == ' ' || c == '\t' || c == '\n')
		{
			c = readChar();
		}

		return c;
	}

	public List<Simbolo> getListaSimbolos()
	{
		return listaSimbolos;
	}
}
